﻿using Acr.UserDialogs;
using Plugin.BLE.Abstractions;
using Plugin.BLE.Abstractions.Contracts;
using RaceHFTools.BluetoothLE;
using RaceHFTools.BluetoothLE.Bean;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace RaceHFTools.Pages
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ScanPage : ContentPage
    {
        private readonly Controller controller;

        class TargetInfo
        {
            public IDevice Target { get; }

            public string Name { get { return Target.Name; } }

            public string Detail
            {
                get
                {
                    byte[] data = GetManufacturerData(Target.AdvertisementRecords.ToArray());
                    if (data != null)
                        return ManufacturerDataToString(data);
                    return string.Empty;
                }
            }


            public TargetInfo(IDevice target)
            {
                Target = target;
            }

            static string ManufacturerDataToString(byte[] data)
            {
                StringBuilder sb = new StringBuilder();
                if (data.Length == 14 && BitConverter.ToUInt16(data, 0) == 0xffff)
                {
                    int st_offset = 2 + 6;
                    sb.Append($"bat-{data[st_offset + 0]}  ");
                    sb.Append($"chg-{data[st_offset + 1]}  ");
                    sb.Append($"fls-{data[st_offset + 2]}  ");
                    sb.Append($"sdc-{data[st_offset + 3]}  ");
                    sb.Append($"gps-{data[st_offset + 4]}  ");
                    sb.Append($"acc-{data[st_offset + 5]}  ");
                }
                return sb.ToString();
            }

            static byte[] GetManufacturerData(AdvertisementRecord[] records)
            {
                foreach (AdvertisementRecord r in records)
                {
                    if (r.Type == AdvertisementRecordType.ManufacturerSpecificData)
                        return r.Data;
                }
                return null;
            }
        }

        readonly ObservableCollection<TargetInfo> ListViewSource = new ObservableCollection<TargetInfo>();
        Product ConnectedPorduct;

        public ScanPage()
        {
            InitializeComponent();

            controller = new Controller();
            lvTargetList.ItemsSource = ListViewSource;
        }

        #region OnAppearing/OnDisappearing
        protected override void OnAppearing()
        {
            base.OnAppearing();

            ListViewSource.Clear();
            lvTargetList.BeginRefresh();

            Task.Run(async () =>
            {
                await Task.Delay(200);
                if (ConnectedPorduct != null && ConnectedPorduct.IsConnect)
                {
                    await ConnectedPorduct.Transport.Disconnect();
                    ConnectedPorduct = null;
                }
            });
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();
        }
        #endregion

        #region 事件处理
        void OnTargetFind(object sender, IDevice target)
        {
            ListViewSource.Add(new TargetInfo(target));
        }

        void OnTargetConnect(object sender, IDevice target)
        {
            Task.Run(async () =>
            {
                Bean bean = new Bean(controller, target);
                bean.Name = target.Name;
                await bean.PreInit();
                ConnectedPorduct = bean;
                Xamarin.Forms.Device.BeginInvokeOnMainThread(async () => await Navigation.PushAsync(new InfoPage(bean) { Title = target.Name }));
            });
        }

        void DoTargetScan()
        {
            static bool target_filter(IDevice target)
            {
                int rssi = target.Rssi;
                string name = target.Name;

                if (rssi < -95)
                    return false;

                if (string.IsNullOrEmpty(name))
                    return false;

                if (Xamarin.Forms.Device.RuntimePlatform == Xamarin.Forms.Device.Android)
                {
                    AdvertisementRecord[] records = target.AdvertisementRecords?.ToArray();
                    foreach (AdvertisementRecord record in records)
                    {
                        if (record.Type == AdvertisementRecordType.UuidsIncomple16Bit)
                        {
                            byte[] data = record.Data;
                            ushort[] uuids = new ushort[data.Length / 2];
                            for (int i = 0; i < uuids.Length; i++)
                                uuids[i] = BitConverter.ToUInt16(data, i * 2);
                            if (Array.IndexOf(uuids, (ushort)0xa0aa) >= 0 && Array.IndexOf(uuids, (ushort)0xf0ff) >= 0)
                                return true;
                        }
                    }
                }
                else
                {
                    return true;
                }

                return false;
            }

            Task.Run(async () =>
            {
                ListViewSource.Clear();

                CancellationTokenSource cts = new CancellationTokenSource();
                using var loading = UserDialogs.Instance.Loading("发现设备", cts.Cancel, "[取消]");
                controller.OnDiscover += OnTargetFind;
                await controller.Scan(5000, filter: target_filter, ct: cts.Token);
                controller.OnDiscover -= OnTargetFind;
            });
        }

        void DoTargetConnect(TargetInfo df)
        {
            Task.Run(async () =>
            {
                controller.OnConnect += OnTargetConnect;

                CancellationTokenSource cts = new CancellationTokenSource();
                using var loading = UserDialogs.Instance.Loading($"连接到 {df.Name}", cts.Cancel, "[取消]");
                await controller.Connect(df.Target, cts.Token);

                controller.OnConnect -= OnTargetConnect;
            });
        }
        #endregion

        #region 交互事件
        void ToolbarItem_About_Clicked(object sender, EventArgs e)
        {
            string version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(version);
            sb.AppendLine("本软件仅限RaceHF内部使用，严禁外传");

            DisplayAlert("关于", sb.ToString(), "确定");
        }

        void Button_ScanTarget_Clicked(object sender, EventArgs e)
        {
            DoTargetScan();
        }

        void ListView_TargetList_ItemTapped(object sender, ItemTappedEventArgs e)
        {
            DoTargetConnect(e.Item as TargetInfo);
        }

        void ListView_TargetList_Refreshing(object sender, EventArgs e)
        {
            DoTargetScan();
            lvTargetList.EndRefresh();
        }
        #endregion
    }
}
